package xyz.heyaoshare.exceptions;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import xyz.heyaoshare.common.entity.bo.Result;
import xyz.heyaoshare.exceptions.customize.ServerException;
import xyz.heyaoshare.utils.HttpUtils;

import static xyz.heyaoshare.exceptions.code.ErrorInfo.BAD_REQUEST;
import static xyz.heyaoshare.exceptions.code.ErrorInfo.METHOD_NOT_ALLOWED;

/**
 * 全局异常处理器
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 上午10:22
 */
@Data
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @SneakyThrows
    @ExceptionHandler(Exception.class)
    public void exceptionHandler(Exception e) {
        HttpServletResponse response = HttpUtils.getResponse();
        assert response != null;
        response.setStatus(500);
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.getWriter().write(JSONUtil.toJsonStr(Result.error()));
    }

    /**
     * 处理 ServerException 异常的方法
     *
     * @param e ServerException 异常对象
     * @return 包含错误信息的响应对象
     */
    @ExceptionHandler(ServerException.class)
    public Result<?> serverExceptionExceptionHandler(ServerException e) {
        HttpServletResponse response = HttpUtils.getResponse();
        assert response != null;
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        return Result.error(e.getCode(), e.getMessage());
    }

    /**
     * 处理 HttpRequestMethodNotSupportedException 异常的方法
     *
     * @param ex HttpRequestMethodNotSupportedException 异常对象
     * @return 包含错误信息的响应对象
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException ex) {
        log.error("[httpRequestMethodNotSupportedExceptionHandler]", ex);
        return Result.error(METHOD_NOT_ALLOWED.getCode(), String.format("请求方法不正确:%s", ex.getMessage()));
    }

    /**
     * 处理缺失HTTP请求参数异常的方法。
     *
     * @param ex 缺失请求参数异常对象
     * @return 响应对象，包含错误信息
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public Result<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) {
        log.error("[missingServletRequestParameterExceptionHandler]", ex);
        return Result.error(BAD_REQUEST.getCode(), String.format("请求参数缺失:%s", ex.getParameterName()));
    }

    /**
     * 处理方法参数类型不匹配的异常。
     *
     * @param ex 方法参数类型不匹配的异常对象
     * @return 包含错误信息的响应对象
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<?> methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException ex) {
        log.error("[missingServletRequestParameterExceptionHandler]", ex);
        return Result.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", ex.getMessage()));
    }

    /**
     * 异常处理器，用于处理方法参数验证失败的情况。
     *
     * @param ex 方法参数验证失败的异常
     * @return 返回R对象，包含错误信息和状态码
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> methodArgumentNotValidExceptionExceptionHandler(MethodArgumentNotValidException ex) {
        log.error("[methodArgumentNotValidExceptionExceptionHandler]", ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        assert fieldError != null; // 断言，避免告警
        log.error(String.format("请求参数不正确:%s", fieldError.getDefaultMessage()));
        return Result.error(BAD_REQUEST.getCode(), fieldError.getDefaultMessage());
    }

    /**
     * 绑定异常处理器
     *
     * @param ex 绑定异常对象
     * @return 响应对象，包含错误码和错误信息
     */
    @ExceptionHandler(BindException.class)
    public Result<?> bindExceptionHandler(BindException ex) {
        log.error("[handleBindException]", ex);
        FieldError fieldError = ex.getFieldError();
        assert fieldError != null; // 断言，避免告警
        String message = fieldError.getDefaultMessage();
        return Result.error(BAD_REQUEST.getCode(), StrUtil.isNotBlank(message) ? message : "请求参数异常");
    }

    /**
     * 处理ConstraintViolationException异常的处理器。
     *
     * @param ex ConstraintViolationException异常对象
     * @return R<?>类型的响应对象，包含错误码和错误信息
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Result<?> constraintViolationExceptionHandler(ConstraintViolationException ex) {
        log.error("[constraintViolationExceptionHandler]", ex);
        ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
        String message = constraintViolation.getMessage();
        return Result.error(BAD_REQUEST.getCode(), StrUtil.isNotBlank(message) ? message : "请求参数异常");
    }

//    @ExceptionHandler(value = NotLoginException.class)
//    public R<?> NotLoginException(NotLoginException ex) {
//        log.error("[constraintViolationExceptionHandler]", ex);
//        return R.error(BAD_REQUEST.getCode(), StrUtil.isNotBlank("") ? "" : "请求参数异常");
//    }
}